# -*- coding: UTF-8 -*-
# File date: Hi_2022/12/12 19:21
# File_name: pillow_method.py
import os
import sys
import time
from itertools import cycle
from os.path import join, abspath
from tkinter import PhotoImage as tkphotoimage
from tkinter.ttk import Label
from typing import Union, Tuple, List
from PIL import Image, ImageSequence
from PIL.ImageTk import PhotoImage
# from typing_extensions import Literal
from typing import Literal
from win11toast import notify

from log_out import log_out
from threading import Thread

# 日志
logger = log_out()

# 提高图像炸弹警告上限
Image.MAX_IMAGE_PIXELS = 1000000000


class pillow_tool:

    @staticmethod
    def get_resource_path(relative_path: str):
        """
        根据传入相对路径获取资源路径
        在需要用到非py文件时用get_resource_path(path)替换原本直接使用相对路径方式即可
        此方法适用于，在进行pyinstaller打包加了-F参数情况，否则建议不使用此方法获得更小的包
        """
        if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
            return join(sys._MEIPASS, relative_path)
        return os.path.abspath(join(abspath(""), relative_path))

    @staticmethod
    def get_tk_Image(image: str):
        """窗口图标用的"""
        image = pillow_tool.get_resource_path(image)
        return tkphotoimage(file=image)

    @staticmethod
    def get_Image(image_path: str) -> Image.Image:
        """
        获取指定路径图片并返回，Image对象
        :param image_path: 图像路径，传入字符串
        :return: 返回Image对象
        """
        image_path = pillow_tool.get_resource_path(image_path)
        pil_image = Image.open(image_path)
        cp_image = pil_image.copy()
        pil_image.close()
        return cp_image

    @staticmethod
    def get_PhotoImage(image: Union[str, Image.Image]) -> PhotoImage:
        """
        传入图像指定str路径或Image对象
        :param image: 传入Image对象或者图像路径，返回Image对象
        :return:返回PhotoImage对象
        """
        if isinstance(image, str):
            pil_photoimage = PhotoImage(image=pillow_tool.get_Image(image))
        elif isinstance(image, Image.Image):
            pil_photoimage = PhotoImage(image=image)
        else:
            raise ValueError
        return pil_photoimage

    @staticmethod
    def get_image_info(image: str) -> Tuple[str, str, str, str, str]:
        """
        获取image信息并返回
        :param image: Image或str对象
        :return: 返回Image需要的几个信息并返回
        """
        image = pillow_tool.get_resource_path(image)
        image_name = os.path.basename(image)  # 文件名
        image_kb_mb = os.stat(image).st_size  # 文件大小
        image_dir = abspath(image)  # 文件路径

        if 1024 < image_kb_mb < 1024 ** 2:
            image_kb_mb = f"{round(image_kb_mb / 1024, 2)}kb"
        elif 1024 ** 2 < image_kb_mb:
            image_kb_mb = f"{round(image_kb_mb / 1024 ** 2, 2)}mb"
        elif image_kb_mb < 1024:
            image_kb_mb = f"{image_kb_mb}b"
        else:
            raise ValueError

        image = Image.open(image)
        image_width = image.width
        image_height = image.height
        image_mode = image.mode

        return image_name, f"{image_width}x{image_height}", image_mode, image_kb_mb, image_dir

    @staticmethod
    def get_image_format(image: str):
        """
        获取image格式并返回
        :param image: Image或str对象
        :return: 返回Image全大写格式
        """
        image = pillow_tool.get_resource_path(image)
        image_format = os.path.basename(image).split(".")[-1]
        image_format = image_format.upper()  # 小写转换为大写
        return image_format

    @staticmethod
    def get_Image_thumbnail(image: Union[str, Image.Image], sizes: Tuple[int, int]) -> Image.Image:
        """
        将传入图像等比缩放，可能会丢失部分高度
        :param image: 需要缩放图像
        :param sizes:缩放后宽高元组
        :return: 等比缩放后图像
        """
        logger.info(f"准备缩放图片")

        if isinstance(image, str):
            logger.info(f"传入image为字符串")
            image = pillow_tool.get_Image(image)
            image = image.copy()

        elif isinstance(image, Image.Image):
            logger.info(f"传入image为Image对象")
            image = image.copy()

        else:
            logger.warning(f"传入image错误")
            raise ValueError

        logger.info(f"缩放后大小{sizes}")
        image.thumbnail(size=sizes, reducing_gap=5.0)
        return image

    @staticmethod
    def get_Image_box(image: Union[str, Image.Image], size: Tuple[int, int]) -> Image.Image:
        """
        图像长或宽放大到，指定大小后居中裁剪要求长宽
        :param image: 需要剪裁的image对象，可以穿入str/或者Image对象
        :param size:裁剪出来的宽高
        :return:返回裁剪后区域
        """
        if isinstance(image, str):
            image = pillow_tool.get_Image(image)

        # 图片宽高
        image_width = image.width
        image_height = image.height

        # 剪裁区域宽高
        box_width = size[0]
        box_height = size[1]

        # 宽高百分比
        width_percentage = box_width / image_width
        height_percentage = box_height / image_height

        logger.info(f"处理图片宽{image_width} 高{image_height},最终剪裁结果宽{box_width} 高{box_height},宽度比例{width_percentage} 高度比例{height_percentage}")

        # 根据图片宽高和剪裁区域宽高比例判断缩放优先
        if width_percentage == 1 and height_percentage == 1:
            logger.info("图片宽高和剪裁宽高一致直接返回image对象")

        elif image_width * height_percentage >= box_width:
            logger.info("图片宽以高度系数放大时,宽度大于等于剪裁后要求宽度, 以高度百分比作为放大系数")
            enlarge_size = (int(image_width * height_percentage), int(image_height * height_percentage))
            image = pillow_tool.get_Image_resize(image, enlarge_size)
            logger.info("以高度比例作为放大系数,放大图片")
            x1 = (enlarge_size[0] - box_width) // 2
            y1 = (enlarge_size[1] - box_height) // 2
            x2 = x1 + box_width
            y2 = y1 + box_height
            logger.info(f"居中剪裁方法后的图片剪裁区域({x1}, {y1}, {x2}, {y2})")
            image = image.crop(box=(x1, y1, x2, y2))

        else:
            logger.info("图片宽以高度系数放大时,宽度小于剪裁后要求宽度, 以宽度百分比作为放大系数")
            enlarge_size = (int(image_width * width_percentage), int(image_height * width_percentage))
            image = pillow_tool.get_Image_resize(image, enlarge_size)
            logger.info("以宽度比例作为放大系数,放大图片")
            x1 = (enlarge_size[0] - box_width) // 2
            y1 = (enlarge_size[1] - box_height) // 2
            x2 = x1 + box_width
            y2 = y1 + box_height
            logger.info(f"居中剪裁方法后的图片剪裁区域({x1}, {y1}, {x2}, {y2})")
            image = image.crop(box=(x1, y1, x2, y2))

        return image

    @staticmethod
    def get_Image_resize(image: Union[str, Image.Image], sizes: Tuple[int, int]) -> Image.Image:
        """
        将传入图像强制缩放
        :param image: 需要缩放图像Image对象或者地址字符串
        :param sizes:缩放后高宽元组
        :return: 返回强制缩放后的图像
        """
        logger.info(f"准备强制缩放图片大小为:{sizes}")
        if isinstance(image, str):
            image = pillow_tool.get_Image(image)

        logger.info(f"传入图片大小为:{image.size}")

        image = image.resize(size=sizes, reducing_gap=5.0)
        return image

    @staticmethod
    def get_Image_equal(image: Union[str, Image.Image], size: Tuple[int, int]) -> Image.Image:
        """
        将图片等比放大或缩小到指定大小后返回Image对象
        :param image: 需要缩放图像Image对象或者地址字符串
        :param size: 输出尺寸后高宽元组
        """
        if isinstance(image, str):
            image = pillow_tool.get_Image(image)

        # 图片宽高
        image_width = image.width
        image_height = image.height

        # 剪裁区域宽高
        box_width = size[0]
        box_height = size[1]

        # 宽高百分比
        width_percentage = box_width / image_width
        height_percentage = box_height / image_height

        logger.info(f"处理图片宽{image_width} 高{image_height}, 最终缩放结果宽{box_width} 高{box_height}, 宽度比例{width_percentage} 高度比例{height_percentage}")

        # 根据图片宽高和剪裁区域宽高比例判断缩放优先
        if width_percentage == 1 and height_percentage == 1:
            logger.info("图片宽高和剪裁宽高一致直接返回image对象")

        elif image_width * height_percentage <= box_width:
            logger.info("图片宽以高度系数放大时,宽度小于等于剪裁后要求宽度, 以高度百分比作为放大系数")
            enlarge_size = (int(image_width * height_percentage), int(image_height * height_percentage))
            image = pillow_tool.get_Image_resize(image, enlarge_size)

        else:
            logger.info("图片宽以高度系数放大时,宽度大于剪裁后要求宽度, 以宽度百分比作为放大系数")
            enlarge_size = (int(image_width * width_percentage), int(image_height * width_percentage))
            image = pillow_tool.get_Image_resize(image, enlarge_size)

        return image

    @staticmethod
    def get_Image_covert(image: Union[str, Image.Image],
                         mode: Literal["l", "la", "i", "p", "rgb", "rgba", "1", "L", "LA", "I", "P", "RGB", "RGBA"] = "RGB"):
        """
        :param image: 传入图像地址或Image对象
        :param mode: 转换后的显示默认
        :return: 转换显示模式后的Image对象
        """
        logger.info("准备转换图片显示模式")
        if isinstance(image, str):
            image = pillow_tool.get_Image(image)

        logger.info(f"原模式{image.mode},转换后{mode}")

        image = image.convert(mode=mode)
        return image

    @staticmethod
    def get_save_path(image_path: str,
                      save_path: str = "",
                      image_format="",
                      same_dir: bool = False,
                      dir_structure: bool = False):
        """
        传入图像路径，返回带时间戳的
        :param image_path:传入图像字符串地址
        :param image_format:需要转换的格式Literal["png", "jpg", "webp", "gif", "ico", "bmp", "", "PNG", "JPG", "WEBP", "GIF", "ICO", "BMP"]
        :param save_path:保存的目录，只需要传入最顶层的目录即可
        :param same_dir:原目录保存,传入bool
        :param dir_structure:传入bool，为Ture自定义保存时保持目录结构选项。当same_dir为Ture时此选项失效
        :return:带文件格式和时间戳的文件名字符串
        """
        logger.info(f"处理输出文件名,原文件名:{os.path.basename(image_path)}")
        logger.info(f"原目录输出：{same_dir}|自定义目录输出:{save_path}|保持目录结构:{dir_structure}")

        if image_format == "":
            image_format = os.path.basename(image_path).split(".")[-1]
            logger.info(f"未指定输出格式，使用原文件格式{image_format}")

        if same_dir:  # 原目录输出开启
            logger.info("开启原目录输出,只修改文件名字后返回")
            image_original_name = os.path.basename(image_path).split(".")[0]
            image_time = time.strftime("%Y%m%d%H%M%S", time.localtime())
            image_name = f"{image_original_name}_{image_time}.{image_format}"
            logger.info(f"处理后文件名:{image_name}")

            save_path = os.path.dirname(image_path)

            finally_save_path = os.path.abspath(os.path.join(save_path, image_name))
            logger.info(f"原目录输出,最终输出{finally_save_path}")
            return finally_save_path

        elif not same_dir and not dir_structure:  # 原目录输出关闭，且不保持目录结构
            logger.info("原目录输出关闭,保持目录结构关闭,自定义输出目录")
            image_original_name = os.path.basename(image_path).split(".")[0]
            image_time = time.strftime("%Y%m%d%H%M%S", time.localtime())
            image_name = f"{image_original_name}_{image_time}.{image_format}"
            logger.info(f"处理后文件名:{image_name}")

            finally_save_path = os.path.abspath(os.path.join(save_path, image_name))
            logger.info(f"最终输出:{finally_save_path}")
            return finally_save_path

        elif not same_dir and dir_structure:  # 如果非原目录保存且保持目录机构
            logger.info(f"处理输出文件名,原文件名:{os.path.basename(image_path)}")
            image_original_name = os.path.basename(image_path).split(".")[0]
            image_time = time.strftime("%Y%m%d%H%M%S", time.localtime())
            image_name = f"{image_original_name}_{image_time}.{image_format}"
            logger.info(f"处理后文件名:{image_name}")

            logger.info(f"校验图片目录{image_path}")
            logger.info(f"校验图片处理后保存顶层目录{save_path}")
            save_path = os.path.abspath(save_path)
            image_path_split = os.path.dirname(os.path.abspath(image_path)).replace("\\", "/").split("/")
            image_path_split.pop(0)
            for split_path in image_path_split:
                save_path = os.path.join(save_path, split_path)
                if not os.path.exists(save_path):
                    logger.info(f"创建目录:{save_path}")
                    os.mkdir(save_path)

            logger.info(f"处理后保存目录：{save_path}")

            finally_save_path = os.path.abspath(os.path.join(save_path, image_name))
            logger.info(f"最终输出：{finally_save_path}")

            return finally_save_path

    @staticmethod
    def show_toast_error(title: str, message: str):
        """
        弹出错误通知文字提示
        :param title: 通知标题
        :param message: 通知内容
        """
        logger.error(f"处理文件错误通知title:{title}, message:{message}")
        notify(title, message)

    @staticmethod
    def show_image_toast(show_path):
        """
        通知方法,处理完成时调用展示通知的图片
        :param show_path:
        :return:
        """
        logger.info(f"处理文件成功通知show_path:{show_path}")
        image = {'src': show_path, 'placement': 'hero'}  # 通知图片在上
        notify("处理完成", show_path, image=image, duration="1000")

    @staticmethod
    def show_toast_success(title: str, message: str):
        """
        弹出错误通知文字提示
        :param title: 通知标题
        :param message: 通知内容
        """
        logger.error(f"完成通知title:{title}, message:{message}")
        notify(title, message)

    @staticmethod
    def check_int(content: str):
        """
        验证输入内容是否大于零的整数,满足条件则返回Ture
        :param content: 自动传入的内容
        :return: 当输入内容是十进制且大于0不是以0开头,处理期间不返回任何异常返回Ture,反之返回False
        """
        logger.info(f"验证输入内容是否大于零的整数:'{content}'")
        if content == "" or content == "0":
            return True

        try:
            # 判断是否十进制且大于0不是以0开头
            if int(content) >= 0 and not content.startswith("0"):
                return True
            else:
                return False
        except (TypeError, ValueError, BaseException):  # 引发任何错误都返回False
            return False

    @staticmethod
    def check_float_int(content: str):
        """
        验证输入内容是否大于零的整数或浮点数,满足条件则返回Ture
        :param content: 自动传入的内容
        :return: 当输入内容是十进制且大于0不是以0开头,处理期间不返回任何异常返回Ture,反之返回False
        """
        logger.info(f"验证输入内容是否大于零的整数或浮点数:'{content}'")

        try:
            if pillow_tool.check_int(content) or float(content) >= 0:
                return True
            else:
                return False

        except (TypeError, ValueError, BaseException):
            return False

    @staticmethod
    def save_any(image: Image.Image, save_path: str):
        """
        原格式保存不考虑格式压缩等
        :param image: 需要保存Image对象
        :param save_path: 最终保存路径,需要包含文件格式后缀的
        """
        image.save(save_path)
        logger.info("保存成功")
        image.close()

    @staticmethod
    def save_png(image: Union[str, Image.Image], save_path: str, compress_level: int = 6):
        """
        把图片转换为png,保存到指定目录
        :param image: 需要保存Image对象或图像路径
        :param save_path: 最终保存路径
        :param compress_level: png保存compress_level参数
        """
        # Pillow 可以识别、读取和写入包含 `1 `， `L `， `LA` ， `I `， `P `， `RGB `或 `RGBA `数据。从v1.1.7开始支持交错文件。
        if isinstance(image, str):
            image = pillow_tool.get_Image(image)

        image.save(save_path, compress_level=compress_level)
        logger.info("转换为png保存成功")
        image.close()

    @staticmethod
    def save_jpg(image: Union[str, Image.Image], save_path: str, quality: int = 75):
        """
        把图片转换为jpg,保存到指定目录
        :param image: 需要保存Image对象或图像路径
        :param save_path: 保存路径
        :param quality: jpg保存quality参数值
        """
        # Pillow 可以读取包含`L`，`RGB`或 `CMYK`数据的JPEG，JFIF和Adobe JPEG文件。它编写标准和渐进式 JFIF 文件。
        if isinstance(image, str):
            image = pillow_tool.get_Image(image)

        logger.info("转换为jpg保存")
        if image.mode not in ["l", "rgb", "cmyk", "L", "RGB", "CMYK"]:
            logger.info("转换为RGB模式后保存")
            image = pillow_tool.get_Image_covert(image, "RGB")
        image.save(save_path, quality=quality)
        logger.info("转换为jpg保存成功")
        image.close()

    @staticmethod
    def save_webp(image: Union[str, Image.Image], save_path: str, quality: int = 80):
        """
        把图片转换为webp,保存到指定目录
        :param image: 需要保存Image对象或图像路径
        :param save_path: 保存路径
        :param quality: webp保存quality参数值
        """
        # method 质量/速度权衡(0=快，6=慢-好)。默认为4。 lossless 如果存在且为真，则指示WebP编写器使用无损压缩。
        if isinstance(image, str):
            image = pillow_tool.get_Image(image)

        image.save(save_path, quality=quality, method=6)
        logger.info("转换为webp保存成功")
        image.close()

    @staticmethod
    def save_ico(image: Union[str, Image.Image], save_path: str, sizes: List[Tuple[int, int]]):
        """
        把图片转换为ico,保存到指定目录
        :param image: 需要保存Image对象或图像路径
        :param save_path: 保存路径
        :param sizes: ico尺寸
        """
        if isinstance(image, str):
            image = pillow_tool.get_Image(image)

        image.save(save_path, sizes=sizes)
        logger.info("转换为ico保存成功")
        image.close()

    @staticmethod
    def save_bmp(image: Union[str, Image.Image], save_path: str):
        """
        把图片转换为bmp,保存到指定目录
        :param image: 需要保存Image对象或图像路径
        :param save_path: 保存路径
        """
        # 包含 1 ， L ， P 或 RGB 数据
        if isinstance(image, str):
            image = pillow_tool.get_Image(image)

        if image.mode not in ["1", "L", "RGB", "CMYK"]:
            logger.info("转换为RGB模式后保存")
            image = image.convert("RGB")
        image.save(save_path)
        logger.info("转换为bmp保存成功")
        image.close()

    @staticmethod
    def save_gif(images: List[str],
                 save_path: str,
                 size,
                 proc_method="",
                 duration: int = 40):
        """
        把图片转换为gif,保存到指定目录
        :param images: 需要合成gif的图片Image对象或图像路径列表,第一个元素是主图像
        :param save_path: 保存路径
        :param size: 把每一帧图像切割成指定大小后合成
        :param proc_method: 处理图像方法 Literal["", "equal_ratio", "cut", "stretch"]
        :param duration: gif每一帧持续时间
        """
        logger.info(f"尺寸:{size}, 裁剪方法:'{proc_method}', 帧延时:{duration}")
        image_list = list()
        if isinstance(images[0], str):
            for image in images:
                image_format = pillow_tool.get_image_format(image)
                if proc_method == "equal_ratio":  # 等比
                    logger.info(f"等比缩放图像:{image}")
                    if image_format != "GIF":
                        image_list.append(pillow_tool.get_Image_equal(image, size))

                    else:
                        image = pillow_tool.get_Image(image)
                        image_sequence = ImageSequence.Iterator(image)
                        for _Image in image_sequence:
                            image_list.append(pillow_tool.get_Image_equal(_Image.copy(), size))

                elif proc_method == "cut":  # 剪裁
                    logger.info(f"剪裁缩放图像:{image}")

                    if image_format != "GIF":
                        image_list.append(pillow_tool.get_Image_box(image, size))

                    else:
                        image = pillow_tool.get_Image(image)
                        image_sequence = ImageSequence.Iterator(image)
                        for _Image in image_sequence:
                            image_list.append(pillow_tool.get_Image_box(_Image.copy(), size))

                elif proc_method == "stretch":  # 拉伸
                    logger.info(f"拉伸缩放图像:{image}")

                    if image_format != "GIF":
                        image_list.append(pillow_tool.get_Image_resize(image, size))
                    else:
                        image = pillow_tool.get_Image(image)
                        image_sequence = ImageSequence.Iterator(image)
                        for _Image in image_sequence:
                            image_list.append(pillow_tool.get_Image_resize(_Image.copy(), size))

                else:  # 不处理图像尺寸
                    logger.info("无需处理图像尺寸,直接添加所有图像")
                    if image_format != "GIF":
                        image_list.append(pillow_tool.get_Image(image))
                    else:
                        image = pillow_tool.get_Image(image)
                        image_sequence = ImageSequence.Iterator(image)
                        for _Image in image_sequence:
                            image_list.append(_Image.copy())

        logger.info(f"最终图像序列长:{len(image_list)}")
        first_image = image_list[0]
        image_list.pop(0)
        first_image.save(save_path, save_all=True, append_images=image_list, duration=duration)
        logger.info("合成为gif保存成功")

        first_image.close()
        for i in image_list:
            i.close()

    @staticmethod
    def preview_image(image: str, show_label: Label, sizes: Tuple[int, int], show_gif_image):
        """
        传入PhotoImage、Image或str对象，将之展示在Label
        :param image: PhotoImage、Image或str对象
        :param show_label: 显示Label区域
        :param show_gif_image: 显示显示的gif的方法
        :param sizes: 显示宽高元组
        """
        if not sizes:
            logger.error("传入的sizes错误或未传值")
            raise ValueError

        image = pillow_tool.get_resource_path(image)
        image_foramt = os.path.basename(image).split(".")[-1]
        logger.info(f"预览图片格式:'{image_foramt}'")

        if image_foramt != "GIF" and image_foramt != "gif":
            show_gif_image.stop_show()
            logger.info(f"停止gif播放")

            image = pillow_tool.get_Image(image)
            image_width = image.width  # 图像宽
            image_height = image.height  # 图像高

            width_proportion = sizes[0] / image.width  # 宽缩放后比例
            height_proportion = sizes[1] / image.height  # 高缩放后比例

            logger.info(f"图像宽{image_width},  "
                        f"高{image_height}, "
                        f"宽度比例{width_proportion}, "
                        f"高度比例{height_proportion}")

            if image_width < sizes[0] or image_height < sizes[1]:  # 如果长或者宽小于给定预览，则按照比例拉伸
                logger.info(f"图片宽或者高小于显示区域,准备强制拉伸")
                logger.info(f"按照高度比例放大宽度{image_width * height_proportion},显示区域宽度{sizes[0]}")
                if image_width * height_proportion >= sizes[0]:  # 判断图片在显示区域宽拉满时,高度是否溢出
                    logger.info(f"图片缩放以宽度拉满为准")
                    # 高度不溢出：高度小于等显示区域高度，则以宽度作为标准
                    return_width = int(image.width * width_proportion)
                    return_height = int(image.height * width_proportion)
                    logger.info(f"确定图片缩放后宽高:({return_width}, {return_height})")
                else:
                    logger.info(f"图片缩放以高度度拉满为准")
                    # 高度溢出：高度大于显示区域高度，以高度作为标准
                    return_width = int(image.width * height_proportion)
                    return_height = int(image.height * height_proportion)
                    logger.info(f"确定图片缩放后宽高:({return_width}, {return_height})")
                image = pillow_tool.get_Image_resize(image, (return_width, return_height))

            else:  # 如果不小于则直接缩小显示
                logger.info(f"图片宽或者高大于于显示区域,准备强制拉伸")
                image = pillow_tool.get_Image_thumbnail(image, sizes)

            image = pillow_tool.get_PhotoImage(image)
            show_label.config(image=image)
            show_label.image = image

        elif image_foramt == "GIF" or image_foramt == "gif":
            logger.info(f"插入图像为gif,交给preview_gif播放动图")
            show_gif_image.image_path = image
            show_gif_image.size = sizes
            Thread(target=show_gif_image.start_show).start()


class preview_gif(pillow_tool):
    def __init__(self, image_path: str, show_area: Label, size):
        # open the GIF and create a cycle iterator
        self.show_area = show_area
        self.image_path = self.get_resource_path(image_path)
        self.updata_state = False  # gif刷新状态
        self.image_cycle = None  # 轮询序列
        self.framerate = None  # 帧间隔
        self.after_id = None
        self.size = size

    def next_frame(self):
        """更新帧"""
        if self.updata_state:
            image = next(self.image_cycle)
            self.show_area.configure(image=image)
            self.after_id = self.show_area.after(self.framerate, self.next_frame)

    def start_show(self):
        if self.after_id:
            logger.info(f"更新前先结束上一个循环after")
            self.show_area.after_cancel(self.after_id)
            self.stop_show()
        logger.info(f"准备播放新的gif：{self.image_path}")
        with Image.open(self.image_path) as im:
            # 创建帧序列
            sequence = ImageSequence.Iterator(im)
            images = [self.get_PhotoImage(self.get_Image_equal(s, self.size)) for s in sequence]
            self.image_cycle = cycle(images)

            self.framerate = im.info["duration"]  # 帧间隔时间
            logger.info(f"准备播放更新播放gif:{os.path.abspath(self.image_path)},"
                        f"帧间隔{self.framerate},"
                        f"一轮帧序列长度：{len(images)}")

            self.updata_state = True
            # self.show_area.after(self.framerate, self.next_frame)
            self.next_frame()

    def stop_show(self):
        if self.updata_state:
            self.updata_state = False  # gif刷新状态
            self.show_area.configure(image="")
            self.image_cycle = None  # 轮询序列
            self.framerate = None  # 帧间隔
            self.after_id = None


if __name__ == '__main__':
    print(pillow_tool.get_image_format(r"C:\Users\Hi\Desktop\11.gif"))
